
rollout Common_NoorsNormalThief "Normal映射"
(
	group "1.选择Normal来源"
	(
		pickbutton pick_source "选择Normal来源物体" width:180
	)
	
	group "2.选择Normal目标"
	(
        pickbutton pick_target "选择Normal目标物体" width:180
        label lblTargetObjectSelectFace "目标物体将Normal映射哪些面"
        label lblNormalTargetHint1 "备注：" align:#left offset:[0,2]
        label lblNormalTargetHint2 "如果需要只映射部分面的Normal" align:#left
        label lblNormalTargetHint3 "需要在Edit_Poly层级选中这些面" align:#left
	)
	
	group "3.映射Nomral"
	(
		button bt_steal "执行" width:180
	)
    
    fn TransferNormals sObj tObj = 
    (
        start = timestamp()
        --get selected faces using copy instead of snapshot to keep poly :[
        selFaces = #{}
        disableRefMsgs()
        tObjCopy = copy tObj
        if (classof tObjCopy != editable_poly) and (classof tObjCopy != editable_mesh) do converttopoly tObjCopy
        selFaces = getFaceSelection tObjCopy

        print("### Sel Faces")
        print(tObjCopy)
        --if no faces selected, select all
        if selFaces.numberset == 0 do selFaces = #{1..tObjCopy.numfaces}	
        delete tObjCopy
        enableRefMsgs()
        
        --snapshot/xform the source object so we don't mess with it
        sMesh = snapshotasmesh sObj
        sObjSnap = editable_mesh()
        sObjSnap.mesh = sMesh

        mod_tObj = Edit_Normals ()
        mod_tObj.displayLength = 1

        mod_sObjSnap = Edit_Normals ()
        mod_sObjSnap.displayLength = 0

        addmodifier tObj mod_tObj
        addmodifier sObjSnap mod_sObjSnap

        --cache
        _getNormalID = mod_sObjSnap.GetNormalID
        _getNormal = mod_sObjSnap.GetNormal

        _getFaceDegree = mod_tObj.GetFaceDegree
        _getVertexID = mod_tObj.GetVertexID
        _getVertex = mod_tObj.GetVertex
        _getNormalIDt = mod_tObj.getNormalID
        _ConvertVertexSelection = mod_tObj.ConvertVertexSelection
        _setSelection = mod_tObj.SetSelection
        _makeExplicit = mod_tObj.MakeExplicit
        _setNormal = mod_tObj.Setnormal

        nID_Arr = #()
        nVal_Arr = #()
        hitFaceBary_Arr = #()
        faceID_Arr = #()
        done = #()
        
        mpi = MeshProjIntersect()
        mpi.setNode sObjSnap
        mpi.build()
        
        --! editNormals has to be the current selection, with modify panel on !
        select tObj --should be already selected but just in case
        tObjTransform = tObj.transform
        
        max modify mode

        --for each selected face...
        for f in selFaces do
        (
            corners = _getFaceDegree f 
            --for each face corner...
            for c=1 to corners do
            (
                --get vertex ID
                v = _getVertexID f c
                if finditem done v == 0 do
                (
                    try
                    (
                        --get vert closest face barycenter in source mesh
                        --get vert normal ID
                        pos = (_getVertex v)*tObjTransform --world pos
                        mpi.closestFace pos doubleSided:true
                        hitFace = mpi.GetHitFace()+1 --zero based
                        bary = mpi.GetHitBary()
                        nID = _getNormalIDt f c
                        --? should we break the id if only 1 smoothing group ?
                        append hitFaceBary_Arr #(hitFace,bary)
                        append nID_Arr  nID
                    )
                    catch (format "Error on vert:%\n" v)
                    sharedNorm = #{}
                    _ConvertVertexSelection #{v} sharedNorm
                    --if the vertex has only 1 normal, we're done with it
                    --? could be more optimized ?
                    if sharedNorm.numberset == 1 do append done v
                )
            )
        )

        --get normal from source faces barycenters
        select sObjSnap
        --for each hitFace...
        for faceBary in hitFaceBary_Arr do
        (
            f = faceBary[1]
            bary = faceBary[2]
            --get its vertex normals
            n1 = _getNormal (_getNormalID f 1)
            n2 = _getNormal (_getNormalID f 2)
            n3 = _getNormal (_getNormalID f 3)
            --get barycenter normal
            n= (bary.x*n1)+(bary.y*n2)+(bary.z*n3)
            append nVal_Arr n
        )

        --set normals on target object
        select tObj
        subobjectLevel = 1
        disableRefMsgs()
        for i=1 to nID_Arr.count do
        (
            nID = nID_Arr[i]
            n = nVal_Arr[i]
            _setSelection #{nID}
            _MakeExplicit()
            _setNormal nID n
        )
        enableRefMsgs()

        --clean
        mpi.Free()
        delete sObjSnap
        gc light:true

        select tObj
        format "Normals transfer took % seconds\n" ((timestamp()-start)/1000.0)
    )

	on pick_source picked obj do
	(
		if obj != undefined do pick_source.text = obj.name
	)
	
	on pick_target picked obj do
	(
		if obj != undefined do pick_target.text = obj.name
        local tempSelectFaceBitArray = getFaceSelection obj
        local totalFaceNum = 0

        if (classOf obj == Editable_mesh) then
        (
            totalFaceNum = meshop.getNumFaces obj
        )
        else if (classOf obj == Editable_Poly) then
        (
            totalFaceNum = polyop.getNumfaces obj
        )

        if tempSelectFaceBitArray.numberSet == 0 then
        (
            lblTargetObjectSelectFace.text = "目标物体将Normal映射 所有面"
        )
        else if tempSelectFaceBitArray.numberSet == totalFaceNum then
        (
            lblTargetObjectSelectFace.text = "目标物体将Normal映射 所有面"
        )
        else
        (
            lblTargetObjectSelectFace.text = "目标物体将Normal映射 选中的面"
        )
	)
	
	on bt_steal pressed  do
	(	
		source = pick_source.object 
		target = pick_target.object 

		if (source != undefined) and (target != undefined) then 
		(
			if (superclassof source == geometryclass) and (superclassof target == geometryclass) then
			(
				format "Source: %\n" source
				format "Target: %\n" target
				TransferNormals source target
			)
			else(messageBox "Souce or Target are not valid geometry objects." title:"Oops !" )
		)
		else(messageBox "Please set a Source Object and select a Target Object ." title:"Oops !" )
	)
)